package mGraph;

import java.util.Hashtable;
import java.util.Set;
import java.util.Vector;

public class MTGraphMeasure {
	
	private MTGraph g;

	public MTGraphMeasure(MTGraph g){
		this.g = g;
	}
	

	/**
	 * Computes the ratio of nodes of the network that belongs to each dimension.
	 * #nodes_on_dimension_d/#dimensions
	 * 
	 * @return An Hashtable having as keys the dimension and as value the computed ratio.
	 */
	public Hashtable<Integer,Double> getNodeDimensionDegree(){
		
		Hashtable<Integer, Double> result = new Hashtable<Integer, Double>();
		
		Set<Integer> nodes = g.nodes.keySet();
		
		for(Integer id_n: nodes){
			Set<Integer> dimensons_n = g.nodes.get(id_n).getDimensions();
			
			for(int i=0;i<g.getDimension();i++){
				if(dimensons_n.contains(new Integer(i))){
					Double dim = result.get(i);
					if(dim==null){
						result.put(i, 1.0);
					}
					else{
						dim = dim+1;
						result.put(i, dim);
					}
				}
			}
			
		}
		
		Set<Integer> result_key = result.keySet();
		for(Integer key:result_key){
			
			result.put(key, (double) result.get(key)/g.getDimension());
		}
		
		
		return result;
	}
	

	/**
	 * Computes the ratio of nodes belonging to both the dimensions over the total number 
	 * of nodes belonging to at least one of them.
	 * 
	 * @param d1 First dimension
	 * @param d2 Second dimension
	 * @return The ratio computed.
	 */
	@SuppressWarnings("unchecked")
	public double getNodeCorrelation(Integer d1, Integer d2){
	
		Vector<Integer> nodi_d1 = new Vector<Integer>(); 
		Vector<Integer> nodi_d2 = new Vector<Integer>(); 
		
		Set<Integer> nodes_ids = g.nodes.keySet();
		
		for(Integer id_n: nodes_ids){
			Set<Integer> dimensions = g.nodes.get(id_n).getDimensions();
			if(dimensions.contains(d1)) nodi_d1.add(id_n); 
			if(dimensions.contains(d2)) nodi_d2.add(id_n); 
		}
		
		Vector<Integer> union = (Vector<Integer>) nodi_d1.clone();
		
		for(Integer u:nodi_d2){
			if(!union.contains(u)) union.add(u);
		}
		
		
		nodi_d1.retainAll(nodi_d2);

		return (double) nodi_d1.size()/union.size();
	}

	/**
	 * Computes the overall correlation in the whole network, giving an idea of the total
	 * redundancy residing in the different dimensions of the network in terms of nodes.
	 * 
	 * @param dim A set of dimensions
	 * @return The ratio computed
	 */
	public double getAvgNodeCorrelation(){
		
		double partial = 0;
		
		for (int i=0; i<g.getDimension();i++){
			for (int j=i+1; j<g.getDimension(); j++){
				 partial += getNodeCorrelation(i,j);
			}
		}
		
		return (double) partial/g.getDimension();
	}


	/**
	 * Computes the ratio of nodes belonging to "child" that belongs also to "parent"
	 * 
	 * @param child A dimension
	 * @param parent A dimension
	 * @return The ratio computed.
	 */
	@SuppressWarnings("unchecked")
	public double getNodeParent(Integer child,Integer parent){
		Vector<Integer> nodi_child = new Vector<Integer>(); 
		Vector<Integer> nodi_parent = new Vector<Integer>(); 
		
		Set<Integer> nodes_ids = g.nodes.keySet();
		
		for(Integer id_n: nodes_ids){
			Set<Integer> dimensions = g.nodes.get(id_n).getDimensions();
			if(dimensions.contains(child)) nodi_child.add(id_n); 
			if(dimensions.contains(parent)) nodi_parent.add(id_n); 
		}
		
		Vector<Integer> intersect = (Vector<Integer>) nodi_child.clone();
		intersect.retainAll(nodi_parent);
		
		return (double) intersect.size()/nodi_child.size();
	}
	
	/**
	 * Computes the ratio of edges belonging to "child" that belongs also to "parent"
	 * 
	 * @param child
	 * @param parent
	 * @return
	 */
	public double getEdgeParent(Integer child,Integer parent){
		Vector<MTEdge> child_edges = g.getEdgesOnDimension(child);
		Vector<MTEdge> parent_edges = g.getEdgesOnDimension(parent);
		
		Hashtable<MTEdge,Integer> retained = new Hashtable<MTEdge,Integer>();
		for(MTEdge e:parent_edges){
			retained.put(e,0);
		}
		
		if((child_edges!=null && parent_edges!=null) && child_edges.size()>0){
			for(MTEdge e: child_edges){
				if(retained.containsKey(e)) retained.remove(e);
			}
			
			
			return (double) retained.size()/child_edges.size();
		}
		
		else return 0.0;
	}
	
	/**
	 * Computes the ratio of edges belonging to both the dimensions over the total number 
	 * of edges belonging to at least one of them.
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	public double getEdgeCorrelation(Integer d1,Integer d2){
		Vector<MTEdge> d1_edges = g.getEdgesOnDimension(d1);
		Vector<MTEdge> d2_edges = g.getEdgesOnDimension(d2);
		
		
		Hashtable <MTEdge,Integer> unionhas = new Hashtable<MTEdge,Integer>();
		Hashtable <MTEdge,Integer> retain = new Hashtable<MTEdge,Integer>();
		
		if((d1_edges!=null && d2_edges!=null)){
			for(MTEdge u:d2_edges){
				if(!unionhas.containsKey(u)) unionhas.put(u,0);
				retain.put(u,0);
			}
			for(MTEdge u:d1_edges){
				if(!unionhas.containsKey(u)) unionhas.put(u,0);
				if(retain.containsKey(u)) retain.remove(u);
			}
			
			if(unionhas.size()>0) 
				return (double) retain.size()/unionhas.size();
			else return 0.0;
		}
	
		else return 0.0;
	}


	
}
